﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data;

namespace DbfTools
{
	public static class ListSavingExtentions
	{
		public static void SaveToFile(this string text, string filename)
		{
			using (var file = new StreamWriter(filename, false, Encoding.GetEncoding(1251)))
				file.Write(text);
		}

		public static void SaveBin<T>(this IEnumerable<T> set, string fileName)
		{
			using (var file = File.Create(fileName))
				new BinaryFormatter().Serialize(file, new List<T>(set));
		}
		public static List<T> LoadBin<T>(this List<T> list, string fileName)
		{
			List<T> tmpList;
			using (var file = File.OpenRead(fileName))
				tmpList = (List<T>)new BinaryFormatter().Deserialize(file);
			list.Clear();
			list.AddRange(tmpList);
			return list;
		}

		public static DataTable SavableToTable<T>(this IEnumerable<T> list)
			where T : ITableSavable<T>, new()
		{
			var table = new DataTable();
			int columnIdexer = 0;
			table.Columns.AddRange(new T().GetColumnTypes()
				.Select(type => new DataColumn("N" + columnIdexer++, type))
				.ToArray());
			table.AddRows(list
				.Select(item => item.GetRowArray()));
			return table;
		}
		public static DataTable ToTable<T>(this IEnumerable<T> list)
		{
			var properies = typeof(T).GetProperties();
			var getters = Array.ConvertAll(properies, prop => (Func<object, object>)(obj => prop.GetValue(obj, null)));
			var table = new DataTable()
				.AddColumns(properies.Select(prop =>
					new DataColumn(prop.Name, prop.PropertyType)))
				.AddRows(list.Select(record =>
					Array.ConvertAll(getters, getter => getter(record))));

			return table;
		}
		public static List<T> FromTable<T>(this List<T> list, DataTable table)
			where T : ITableSavable<T>, new()
		{
			list.Clear();
			list.AddRange(table.RowsList()
				.Select(row => new T().ParseRow(row.ItemArray)));
			return list;
		}
	}
	public static class Csv
	{
		public static IEnumerable<T> SaveCsv<T>(this IEnumerable<T> list, string fileName)
			where T : ISavable<T>, new()
		{
			using (var file = new StreamWriter(fileName, false, Encoding.GetEncoding(1251)))
				foreach (var line in list)
					file.WriteLine(line.GetCsvString());
			return list;
		}
		public static List<T> Load<T>(string fileName)
			where T : ISavable<T>, new()
		{
			string text;
			using (var file = new StreamReader(fileName, Encoding.GetEncoding(1251)))
				text = file.ReadToEnd();
			return text
				.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
				.Select(line => new T().ParseCsvString(line.TrimEnd('\r')))
				.ToList();
		}
		public interface ISavable<T>
		{
			string GetCsvString();
			T ParseCsvString(string str);
		}
	}
	public interface ITableSavable<T>
	{
		Type[] GetColumnTypes();
		object[] GetRowArray();
		T ParseRow(object[] row);
	}
}
